package org.langcom.buffer;

// Hijack these for simplicity
import java.io.Serializable;
import java.util.Arrays;

public class CircularBuffer<T> implements Serializable {

	private static final long serialVersionUID = -6830856052685418299L;
	private T[] buffer;
	private int head = 0;

	@SuppressWarnings("unchecked")
	public CircularBuffer(int n) {
		buffer = (T[]) new Object[n];
	}

	public CircularBuffer(T[] bufferIn) {
		buffer = bufferIn;
	}

	/*
	 * add last element and moveheader
	 */
	public void add(T toAdd) {
		buffer[head++] = toAdd;
		// if (head >= buffer.length) {
		// head = 0;
		// }
		head = head % buffer.length;
	}

	public void push() {
		if (buffer.length == 0) {
			return;
		}
		head++;
		// if (head >= buffer.length) {
		// head = 0;
		// }
		head = head % buffer.length;
	}

	public String toString() {
		return "CircularBuffer(size=" + buffer.length + ", head=" + head + ")";
	}

	@SuppressWarnings("unchecked")
	public Object[] getBuffer() {
		T[] result = (T[]) new Object[buffer.length];
		int start = head - 1;
		if (start < 0) {
			start = buffer.length - 1;
		}
		int end = start;
		int count = 0;
		do {
			if (start < 0 || count == result.length) {
				break;
			}
			result[count++] = buffer[start];
			start = start - 1;
			if (start < 0) {
				start = buffer.length - 1;
			}
		} while (start != end);
		return result;
	}

	public int size() {
		return buffer.length;
	}

	public T getHead() {
		synchronized (buffer) {
			if (buffer.length == 0) {
				return null;
			}
			if (buffer[head] == null) {
				return buffer[head > 0 ? head - 1 : 0];
			}
			return buffer[head];
		}
	}

	public T getLast() {
		synchronized (buffer) {
			int dd = head - 1;
			T last = null;
			if (dd >= 0) {
				last = buffer[dd];
			} else {
				last = buffer[buffer.length - 1];
			}
			return last;
		}
	}

	public int head() {
		return head;
	}

	public static void main(String[] args) {
		CircularBuffer<Integer> bb = new CircularBuffer<Integer>(5);
		bb.add(4);
		System.out.println("--------" + bb.getHead());
		bb.add(5);
		System.out.println("--------" + bb.getHead());
		bb.add(6);
		System.out.println("--------" + bb.getHead());
		bb.add(7);
		System.out.println("--------" + bb.getHead());
		bb.add(8);
		System.out.println(Arrays.toString(bb.getBuffer()) + "--------" + bb.getHead());
		System.out.println("--------" + bb.getHead());
		bb.add(9);
		System.out.println(Arrays.toString(bb.getBuffer()) + "--------" + bb.getHead());
		System.out.println("--------" + bb.getHead());
		bb.add(10);
		System.out.println(Arrays.toString(bb.getBuffer()) + "--------" + bb.getHead());
		System.out.println("--------" + bb.getHead());
		bb.push();
		System.out.println("--------" + bb.getHead());
		bb.push();
		System.out.println("--------" + bb.getHead());
		bb.push();
		System.out.println("--------" + bb.getHead());
		bb.push();
		System.out.println("--------" + bb.getHead());
		bb.push();
		System.out.println("--------" + bb.getHead());
		bb.push();
		System.out.println("--------" + bb.getHead());
		bb.push();
		System.out.println("--------" + bb.getHead());
		bb.push();
		System.out.println("--------" + bb.getHead());
		bb.push();
		System.out.println("--------" + bb.getHead());
		bb.push();
		System.out.println("--------" + bb.getHead());
	}
}
